#region license
# This file is part of Grawlix.
# 
# Grawlix is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
# 
# Grawlix is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public
# License along with Grawlix.  If not, see
# <http://www.gnu.org/licenses/>.
#endregion

"""Primitive rectangle structure."""

namespace Grawlix
import Grawlix.Meta
import System

struct Rect:
"""A simple rectangle in the cartesian plane."""
	
	def constructor(x1 as double,
	                y1 as double,
	                x2 as double,
	                y2 as double):
	"""
	Create a new rectangle from four values.
	Param x1: Minimum x coordinate. (Left)
	Param y1: Minimum y coordinate. (Bottom)
	Param x2: Maximum x coordinate. (Right)
	Param y2: Maximum y coordinate. (Top)
	"""
		self(Vector(x1, y1), Vector(x2, y2))
	
	def constructor(minimum as Vector, maximum as Vector):
	"""
	Create a rectangle by specifying its corners.
	Param minimum: The bottom-left corner.
	Param maximum: The top-right corner.
	"""
		_min = minimum
		_max = maximum
	
	def Contains(point as Vector):
	"""
	Whether a point is fully inside this rect.
	Param point: The interior point.
	Returns: true if this rect contains the specified point.
	"""
		return (point.Y <= Top and
		    	point.Y >= Bottom and
		    	point.X >= Left and
		    	point.X <= Right)
	
	def Contains(rect as Rect):
	"""
	Whether a rect is fully inside this rect (or equal in area).
	Param rect: The interior rectangle.
	Returns: true if this rect contains the specified rect.
	"""
		return (rect.Top <= Top and
		    	rect.Bottom >= Bottom and
		    	rect.Left >= Left and
		    	rect.Right <= Right)
	
	def ProjectPoint(point as Vector, target as Rect):
	"""
	Project a position from this rectangle to another.
	Param point: The original position.
	Param target: The new rectangle.
	Returns: The position within the new rectangle.
	"""
		point -= Min
		point.X /= Width
		point.Y /= Height
		point.X *= target.Width
		point.Y *= target.Height
		point += target.Min
		return point
	
	def ProjectDisplacement(displacement as Vector, target as Rect):
	"""
	Project a displacement from one rectangle to another.
	Param displacement: The original displacement.
	Param target: The new rectangle.
	Returns: The displacement within the new rectangle.
	"""
		displacement.X /= Width
		displacement.Y /= Height
		displacement.X *= target.Width
		displacement.Y *= target.Height
		return displacement
	
	[Duplicate(Add)]
	[Duplicate(Add, ApplyToSelf: true)]
	static def op_Addition(rect as Rect, vector as Vector):
	"""
	Displace a rectangle by a vector.
	Param rect: The rect to displace.
	Param v: The vector to use to displace it.
	Returns: The displaced vector.
	"""
		return Rect(rect.Min + vector, rect.Max + vector)
	
	[Duplicate(Add)]
	static def op_Addition(vector as Vector, rect as Rect):
	"""
	Displace a rectangle by a vector.
	Param v: The vector to use to displace the rect.
	Param rect: The rect to displace.
	Returns: The displaced vector.
	"""
		return op_Addition(rect, vector)
	
	[Duplicate(Subtract)]
	[Duplicate(Subtract, ApplyToSelf: true)]
	static def op_Subtraction(rect as Rect, vector as Vector):
	"""
	Displace a rectangle by a vector.
	Param rect: The rect to displace.
	Param v: The vector whose negation is used to displace it.
	Returns: The displaced vector.
	"""
		return op_Addition(rect, -vector)
	
	[Duplicate(Subtract)]
	static def op_Subtraction(vector as Vector, rect as Rect):
	"""Displace a rectangle by a negated vector."""
		return op_Addition(rect, -vector)
	
	[Equality(OverloadOperators: true)]
	private def Equality(other as Rect):
	"""
	Equality testing.
	Param other: The rect to compare to.
	Returns: true if equal, else false.
	"""
		return (Min == other.Min and Max == other.Max)
	
	override def GetHashCode():
	"""
	A hash code based on the current value.
	Returns: The hash code.
	"""
		return Min.GetHashCode() ^ Max.GetHashCode()
	
	override def ToString():
	"""
	Get a string representation for this object.
	Returns: A string representation for this object.
	"""
		return "(${Min}; ${Max})"
	
	[property(Min)]
	private _min as Vector
	"""The bottom-left corner of the rectangle."""
	
	[property(Max)]
	private _max as Vector
	"""The top-right corner of the rectangle."""
	
	Dimensions as Vector:
	"""The dimensions of the rectangle."""
		get:
			return _max - _min
	
	Left:
	"""The left border of the rectangle."""
		get:
			return _min.X
		set:
			_min.X = value
	
	Bottom:
	"""The bottom border of the rectangle."""
		get:
			return _min.Y
		set:
			_min.Y = value
	
	Right:
	"""The right border of the rectangle."""
		get:
			return _max.X
		set:
			_max.X = value
	
	Top:
	"""The top border of the rectangle."""
		get:
			return _max.Y
		set:
			_max.Y = value
	
	Width:
	"""The width of the rectangle."""
		get:
			return Right - Left
	
	Height:
	"""The height of the rectangle."""
		get:
			return Top - Bottom

	